#include "../include/index_cache.h"

IndexCache::IndexCache() {
}

IndexCache::IndexCache(int size) :
    cache_size_(0), cache_items_(0), size_(size), oldest_node_(NULL), newest_node_(
        NULL) {
  try {
    cache_list_ = new IndexStruct[size_];
  } catch (const std::bad_alloc &ex) {
    std::cerr << ex.what() << std::endl;
    exit(-1);
  }

  memset(cache_list_, 0, sizeof(IndexStruct) * size_);

}

IndexCache::~IndexCache() {

  SNode* p = oldest_node_;
  while (p) {
    int id = p->id;
    delete[] cache_list_[id].encode_list;
    p = p->next;
    delete cache_list_[id].pnode;
  }

  delete[] cache_list_;
}

bool IndexCache::find(int id, int& len, char* &encode_list) {
  if (cache_list_[id].pnode) { //hit

    encode_list = cache_list_[id].encode_list;
    len = cache_list_[id].len;

    //do LRU
    SNode* tmp = cache_list_[id].pnode;
    if (tmp != newest_node_) {
      if (tmp == oldest_node_) {
        oldest_node_ = oldest_node_->next;
        oldest_node_->pre = NULL;
      } else {
        tmp->next->pre = tmp->pre;
        tmp->pre->next = tmp->next;
      }
      newest_node_->next = tmp;
      tmp->pre = newest_node_;
      newest_node_ = tmp;
      newest_node_->next = NULL;
    }

    return true;
  }
  // miss
  return false;
}

bool IndexCache::set(int id, int len, char* encode_list) {
  while (oldest_node_ && len + cache_size_ > MAXCACHESIZE) {
    int remove_id = oldest_node_->id;
    if (cache_list_[remove_id].encode_list) {
      delete[] cache_list_[remove_id].encode_list;
      cache_list_[remove_id].encode_list = NULL;
    }
    cache_list_[remove_id].pnode = NULL;
    cache_size_ -= cache_list_[remove_id].len;
    cache_list_[remove_id].len = 0;
    --cache_items_;
    SNode* tmp = oldest_node_;
    oldest_node_ = oldest_node_->next;
    delete tmp;
    tmp = NULL;
  }

  if (oldest_node_ == NULL)
    newest_node_ = NULL;
  else
    oldest_node_->pre = NULL;

  cache_list_[id].len = len;
  cache_list_[id].encode_list = encode_list;

  try {
    cache_list_[id].pnode = new SNode;
  } catch (const std::bad_alloc &ex) {
    std::cerr << ex.what() << std::endl;
    return false;
  }

  cache_list_[id].pnode->id = id;
  cache_list_[id].pnode->next = NULL;
  cache_list_[id].pnode->pre = NULL;

  if (oldest_node_ == NULL) {
    oldest_node_ = cache_list_[id].pnode;
    newest_node_ = oldest_node_;
  } else {
    cache_list_[id].pnode->pre = newest_node_;
    newest_node_->next = cache_list_[id].pnode;
    newest_node_ = newest_node_->next;
  }

  cache_size_ += len;
  ++cache_items_;
  return true;
}
